package com.kacheong.pms.dao.impl;

import com.kacheong.pms.POJO.PageBean;
import com.kacheong.pms.dao.IBaseDao;
import org.hibernate.Query;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate5.HibernateTemplate;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

/**
 * Created by kacheong on 2017/11/17.
 */

public class BaseDao<T> implements IBaseDao<T> {
    private static final Logger logger = LoggerFactory.getLogger(BaseDao.class);

    @Autowired
    private HibernateTemplate hibernateTemplate;

    private Class entityClass;

    public BaseDao() {
        init();
    }

    @Override
    public T get(Serializable id) {
        return (T) hibernateTemplate.get(entityClass,id);
    }

    @Override
    public List<T> list() {
        return hibernateTemplate.loadAll(entityClass);
    }

    @Override
    @Transactional(readOnly = false)
    public Serializable save(T entity) {
        logger.info("save: " + entity.toString());
        Serializable id = getHibernateTemplate().save(entity);
        return id;
    }

    @Override
    @Transactional(readOnly = false)
    public boolean update(T entity) {
        logger.info("update: " + entity.toString());
        getHibernateTemplate().update(entity);
        return true;
    }

    @Override
    public int update(String HQL, Object... param) {
        return getHibernateTemplate().execute(session -> {
            Query query = session.createQuery(HQL);
            if (param != null) {
                for (int i = 0; i < param.length; i++) {
                    query.setParameter(i, param[i]);
                }
            }
            return query.executeUpdate();
        });
    }

    @Override
    @Transactional(readOnly = false)
    public void remove(T entity) {
        logger.info("remove: " + entity.toString());
        getHibernateTemplate().delete(entity);
    }

    @Override
    public PageBean doPage(String HQL, int currentPage, int pageSize, Object... param) {
        Long allRow = count(HQL,param);
        PageBean pageBean = new PageBean(allRow, pageSize, currentPage);
        List l = getHibernateTemplate().execute(session -> {
            Query query = session.createQuery(HQL);
            if (param != null) {
                for (int i = 0; i < param.length; i++) {
                    query.setParameter(i, param[i]);
                }
            }
            query.setFirstResult((pageBean.getCurrentPage() - 1) * pageBean.getPageSize());
            query.setMaxResults(pageBean.getPageSize());
            return query.list();
        });
        pageBean.setList(l);
        return pageBean;
    }

    private final String count = "SELECT COUNT(*) ";
    @Override
    public Long count(String HQL, Object... param) {
        HQL = count + HQL;
        return (Long) getHibernateTemplate().find(HQL,param).listIterator().next();
    }

    protected HibernateTemplate getHibernateTemplate() {
        return hibernateTemplate;
    }

    private void init() {
        Type genType = getClass().getGenericSuperclass();
        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
        entityClass = (Class) params[0];
    }
}
